package model.semantics;

import java.util.*;

import util.reflection.Reflection;

import model.State;

/**
 * Represents an operator within the expression tree.
 * 
 * @author Sterling Dorminey
 * 
 */
public class OperatorNode<T> extends Node<T> {
    private Node<T>[] myChildren;
    private Operation<T> myOperation;

    /**
     * Create a node with the children and the operation to do on the children.
     * 
     * @param operation
     *            the operation to perform.
     * @param values
     *            the children to perform it on.
     */
    public OperatorNode(Operation<T> operation, Node<T>... values) {
        myChildren = Arrays.copyOf(values, values.length);
        myOperation = operation;
    }

    /**
     * Produce a color by evaluating the children.
     * 
     * @param x
     *            the x-coordinate.
     * @param y
     *            the y-coordinate.
     * @return the color.
     */
    @Override
    @SuppressWarnings("unchecked")
    public T evaluate(State<T> state) {
        List<T> values = new ArrayList<T>(myChildren.length);
        for (int i = 0; i < myChildren.length; i++) {
            values.add(myChildren[i].evaluate(state));
        }
        return myOperation.evaluate(state, (T[]) values.toArray());
    }

    /**
     * Does a preorder traversal of the expression tree to print a string for
     * the tree.
     */
    @Override
    public String toString() {
        if (myChildren.length == 0) {
            return String.format("(%s)", myOperation.toString());
        }
        // Get string for argument list.
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < myChildren.length - 1; i++) {
            sb.append(myChildren[i].toString() + ", ");
        }
        sb.append(myChildren[myChildren.length - 1].toString());

        return String.format("(%s %s)", myOperation.toString(), sb.toString());
    }
}
